home *** CD-ROM | disk | FTP | other *** search
- /* unlink.c: by ERS. This routine is in the public domain */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <errno.h>
- #include <osbind.h>
- #include <unixlib.h>
- #include <support.h>
- #include <fcntl.h>
- #include <string.h>
- #include "symdir.h"
- #include "lib.h"
-
- #define error(x) ((errno = (x)), -1)
- __EXTERN char *strdup __PROTO((const char *s));
-
- /* remove provided for ansi compatibility */
- #ifndef __GNUC__
- int remove(filename)
- const char *filename;
- {
- return unlink(filename);
- }
- #endif
-
- static struct delete {
- char *fname;
- struct delete *next;
- } *D = (struct delete *)NULL;
-
- static void
- do_deletes()
- {
- struct delete *d;
-
- d = D;
- while (d) {
- if(d->fname) {
- (void)Fdelete(d->fname);
- free(d->fname);
- }
- d = d->next;
- }
- }
-
- #ifdef __GNUC__
- asm(".stabs \"_remove\",5,0,0,_unlink"); /* dept of clean tricks */
- #endif
- int
- unlink(filename)
- const char * filename;
- {
- char name[FILENAME_MAX];
- char *s;
- int r, fd;
- struct delete *d;
- int nameinfo;
- SYMDIR *dir = 0;
- SYMENTRY *ent = 0, *old;
- /*
- * _unx2dos returns _NM_LINK if "filename" was a symbolic link,
- * in which case __link_path[] is the path to the directory containing
- * the link, and __link_name[] is the name of the link.
- */
- nameinfo = _unx2dos(filename, name);
-
- if (nameinfo == _NM_LINK) { /* a symbolic link */
- if (!(dir = _read_symdir(__link_path)))
- return -1;
- old = 0; ent = dir->s_dir;
- while (ent) {
- if (!strcmp(ent->linkname, __link_name))
- break;
- old = ent; ent = ent->next;
- }
- }
- else if (_lOK && nameinfo == _NM_CHANGE) {
- /* if symlinks are active, insist that the correct file name be given */
- errno = ENOENT;
- return -1;
- }
- /*
- * unlink the real file, if no symbolic link was found (ent == 0)
- * or if the link was an automatic link. Unix allows open files
- * to be unlinked; TOS does not, and to get around this we check
- * the names of all the open files; if the one we want is found,
- * we arrange to unlink it on exit.
- */
-
- if (!ent || (ent->flags & SD_AUTO)) {
- for (fd = 0; fd < __NHANDLES; fd++) {
- if ((s = __open_stat[fd].filename) && !strcmp(s, name)) {
- /* D == 0 means the atexit routine was not installed yet */
- if (!D && atexit(do_deletes)) {
- _free_symdir(dir);
- return error(ENOMEM);
- }
- d = (struct delete *)malloc(sizeof(struct delete));
- if (!d) {
- _free_symdir(dir);
- return error(ENOMEM);
- }
- /* hook the new "delete" structure into the chain */
- d->fname = strdup(name);
- d->next = D; D = d;
- if(!(d->fname)) {
- /* note we link it in and then check, as
- we cannot undo the atexit(), (nor do we
- want to because there maybe others on the
- chain already). in do_deletes we'll
- just skip the null name entries */
- _free_symdir(dir);
- return error(ENOMEM);
- }
-
- /* if there was an automatic link, delete it now */
- if (ent)
- goto unlink_sym;
- return 0;
- }
- }
- r = (int)Fdelete(name);
- }
- /*
- * watch out for delete errors; if we have an auto link to a write
- * protected file, preserve the link; but if the auto link points
- * to a non-existent file, delete it
- */
- if ( ent && r == -EACCESS) {
- _free_symdir(dir);
- return error(-r);
- }
- /*
- * having gotten this far, all that's left is to unlink the symbolic
- * link itself. "old" was set to the previous directory entry; we
- * remove "ent" from the chain, then rewrite the directory.
- */
-
- unlink_sym:
-
- if (ent) {
- if (old)
- old->next = ent->next;
- else
- dir->s_dir = ent->next;
- r = _write_symdir(__link_path,dir);
- _free_symdir(dir);
- }
-
- if (r < 0) {
- return error(-r);
- }
- return 0;
- }
-